// SpringTail : Simple Logging Abstraction block
// Copyright (c) 2008 Michael Saunders <mike@mikesaunders.com>
// All rights reserved.
// Released under Apache License 2.0 <www.apache.org/licenses>
// 
using System;
using NUnit.Framework;
using SpringTail;

namespace TestSpringTail
{
	[TestFixture]
	public class TestLogger
	{
		private Logger _logger;
		private LogMessage _loggedMessage;

		private const string _name = "name";
		private const string _text = "message";
		private readonly object _data = new object();
		private readonly Exception _exception = new Exception("exception");

		[SetUp]
		public void SetUp()
		{
			Logger.LogAction = m => _loggedMessage = m;
			_logger = new Logger(_name, this);
		}

		private void TestMessage(LogLevel logLevel, bool data, bool exception)
		{
			Assert.AreEqual(logLevel, _loggedMessage.Level);
			Assert.AreEqual(_name, _loggedMessage.LoggerName);
			Assert.AreSame(this, _loggedMessage.LoggerOwner);
			Assert.AreEqual(_text, _loggedMessage.Message);

			if (data)
				Assert.AreSame(_data, _loggedMessage.Data);
			else
				Assert.IsNull(_loggedMessage.Data);

			if (exception)
				Assert.AreSame(_exception, _loggedMessage.Exception);
			else
				Assert.IsNull(_loggedMessage.Exception);
		}

		#region Test Constructors
		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Test_Constructor_throws_for_null_name_param()
		{
			new Logger(null);
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Test_Constructor_throws_for_empty_name_param()
		{
			new Logger(string.Empty);
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Test_Constructor2_throws_for_null_name_param()
		{
			new Logger(null, new object());
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Test_Constructor2_throws_for_empty_name_param()
		{
			new Logger(string.Empty, new object());
		}

		[Test]
		public void Test_Constructor2_does_not_throw_for_null_owner()
		{
			new Logger(_name, null);
		}
		#endregion

		#region Test Name
		[Test]
		public void Test_get_Name()
		{
			Assert.AreEqual("name", _logger.Name);
		}
		#endregion

		#region Test Owner
		[Test]
		public void Test_default_get_Owner()
		{
			Logger component = new Logger(_name);
			Assert.IsNull(component.Owner);
		}

		[Test]
		public void Test_get_Owner()
		{
			Assert.AreSame(this, _logger.Owner);

			Logger logger = new Logger(_name, null);
			Assert.IsNull(logger.Owner);
		}
		#endregion

		#region Test Log
		[Test]
		public void Test_Log_with_null_LogAction_is_harmless()
		{
			Logger.LogAction = null;
			_logger.Log(LogLevel.Info, "message");
		}

		[Test]
		public void Test_Log_with_null_message_param()
		{
			_logger.Log(LogLevel.Debug, null);
			Assert.IsNull(_loggedMessage.Message);
		}

		[Test]
		public void Test_Log_Debug()
		{
			_logger.Log(LogLevel.Debug, _text);
			TestMessage(LogLevel.Debug, false, false);
		}

		[Test]
		public void Test_Log_Info()
		{
			_logger.Log(LogLevel.Info, _text);
			TestMessage(LogLevel.Info, false, false);
		}

		[Test]
		public void Test_Log_Warn()
		{
			_logger.Log(LogLevel.Warn, _text);
			TestMessage(LogLevel.Warn, false, false);
		}

		[Test]
		public void Test_Log_Error()
		{
			_logger.Log(LogLevel.Error, _text);
			TestMessage(LogLevel.Error, false, false);
		}

		[Test]
		public void Test_Log_Fatal()
		{
			_logger.Log(LogLevel.Fatal, _text);
			TestMessage(LogLevel.Fatal, false, false);
		}
		#endregion

		#region Test Debug
		[Test]
		public void Test_Debug_does_not_throw_for_null_message_param()
		{
			_logger.Debug(null);
		}

		[Test]
		public void Test_Debug()
		{
			_logger.Debug(_text);
			TestMessage(LogLevel.Debug, false, false);
		}
		#endregion

		#region Test Info
		[Test]
		public void Test_Info_does_not_throw_for_null_message_param()
		{
			_logger.Info(null);
		}

		[Test]
		public void Test_Info()
		{
			_logger.Info(_text);
			TestMessage(LogLevel.Info, false, false);
		}
		#endregion

		#region Test Warn
		[Test]
		public void Test_Warn_does_not_throw_for_null_message_param()
		{
			_logger.Warn(null);
		}

		[Test]
		public void Test_Warn()
		{
			_logger.Warn(_text);
			TestMessage(LogLevel.Warn, false, false);
		}
		#endregion

		#region Test Error
		[Test]
		public void Test_Error_does_not_throw_for_null_message_param()
		{
			_logger.Error(null);
		}

		[Test]
		public void Test_Error()
		{
			_logger.Error(_text);
			TestMessage(LogLevel.Error, false, false);
		}
		#endregion

		#region Test Fatal
		[Test]
		public void Test_Fatal_does_not_throw_for_null_message_param()
		{
			_logger.Fatal(null);
		}

		[Test]
		public void Test_Fatal()
		{
			_logger.Fatal(_text);
			TestMessage(LogLevel.Fatal, false, false);
		}
		#endregion

		#region Test Log with Data
		[Test]
		public void Test_Log_with_data_does_not_throw_for_null_message_param()
		{
			_logger.Log(LogLevel.Debug, null, _data);
		}

		[Test]
		public void Test_Log_with_data_does_not_throw_for_null_data_param()
		{
			_logger.Log(LogLevel.Debug, _text, null);
		}

		[Test]
		public void Test_Log_with_data_Debug()
		{
			_logger.Log(LogLevel.Debug, _text, _data);
			TestMessage(LogLevel.Debug, true, false);
		}

		[Test]
		public void Test_Log_with_data_Info()
		{
			_logger.Log(LogLevel.Info, _text, _data);
			TestMessage(LogLevel.Info, true, false);
		}

		[Test]
		public void Test_Log_with_data_Warn()
		{
			_logger.Log(LogLevel.Warn, _text, _data);
			TestMessage(LogLevel.Warn, true, false);
		}

		[Test]
		public void Test_Log_with_data_Error()
		{
			_logger.Log(LogLevel.Error, _text, _data);
			TestMessage(LogLevel.Error, true, false);
		}

		[Test]
		public void Test_Log_with_data_Fatal()
		{
			_logger.Log(LogLevel.Fatal, _text, _data);
			TestMessage(LogLevel.Fatal, true, false);
		}
		#endregion

		#region Test Debug with Data
		[Test]
		public void Test_Debug_with_data_does_not_throw_for_null_message_param()
		{
			_logger.Debug(null, _data);
		}

		[Test]
		public void Test_Debug_with_data_does_not_throw_for_null_data_param()
		{
			_logger.Debug(_text, null);
		}

		[Test]
		public void Test_Debug_with_data()
		{
			_logger.Debug(_text, _data);
			TestMessage(LogLevel.Debug, true, false);
		}
		#endregion

		#region Test Info with Data
		[Test]
		public void Test_Info_with_data_does_not_throw_for_null_message_param()
		{
			_logger.Info(null, _data);
		}

		[Test]
		public void Test_Info_with_data_does_not_throw_for_null_data_param()
		{
			_logger.Info(_text, null);
		}

		[Test]
		public void Test_Info_with_data()
		{
			_logger.Info(_text, _data);
			TestMessage(LogLevel.Info, true, false);
		}
		#endregion

		#region Test Warn with Data
		[Test]
		public void Test_Warn_with_data_does_not_throw_for_null_message_param()
		{
			_logger.Warn(null, _data);
		}

		[Test]
		public void Test_Warn_with_data_does_not_throw_for_null_data_param()
		{
			_logger.Warn(_text, null);
		}

		[Test]
		public void Test_Warn_with_data()
		{
			_logger.Warn(_text, _data);
			TestMessage(LogLevel.Warn, true, false);
		}
		#endregion

		#region Test Error with Data
		[Test]
		public void Test_Error_with_data_does_not_throw_for_null_message_param()
		{
			_logger.Error(null, _data);
		}

		[Test]
		public void Test_Error_with_data_does_not_throw_for_null_data_param()
		{
			_logger.Error(_text, null);
		}

		[Test]
		public void Test_Error_with_data()
		{
			_logger.Error(_text, _data);
			TestMessage(LogLevel.Error, true, false);
		}
		#endregion

		#region Test Fatal with Data
		[Test]
		public void Test_Fatal_with_data_does_not_throw_for_null_message_param()
		{
			_logger.Fatal(null, _data);
		}

		[Test]
		public void Test_Fatal_with_data_does_not_throw_for_null_data_param()
		{
			_logger.Fatal(_text, null);
		}

		[Test]
		public void Test_Fatal_with_data()
		{
			_logger.Fatal(_text, _data);
			TestMessage(LogLevel.Fatal, true, false);
		}
		#endregion

		#region Test LogException
		[Test]
		public void Test_LogException_does_not_throw_for_null_message_param()
		{
			_logger.LogException(LogLevel.Debug, null, _exception);
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Test_LogException_throws_for_null_exception_param()
		{
			_logger.LogException(LogLevel.Debug, _text, null);
		}

		[Test]
		public void Test_LogException_Debug()
		{
			_logger.LogException(LogLevel.Debug, _text, _exception);
			TestMessage(LogLevel.Debug, false, true);
		}

		[Test]
		public void Test_LogException_Info()
		{
			_logger.LogException(LogLevel.Info, _text, _exception);
			TestMessage(LogLevel.Info, false, true);
		}

		[Test]
		public void Test_LogException_Warn()
		{
			_logger.LogException(LogLevel.Warn, _text, _exception);
			TestMessage(LogLevel.Warn, false, true);
		}

		[Test]
		public void Test_LogException_Error()
		{
			_logger.LogException(LogLevel.Error, _text, _exception);
			TestMessage(LogLevel.Error, false, true);
		}

		[Test]
		public void Test_LogException_Fatal()
		{
			_logger.LogException(LogLevel.Fatal, _text, _exception);
			TestMessage(LogLevel.Fatal, false, true);
		}
		#endregion

		#region Test DebugException
		[Test]
		public void Test_DebugException_does_not_throw_for_null_message_param()
		{
			_logger.DebugException(null, _exception);
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Test_DebugException_throws_for_null_exception_param()
		{
			_logger.DebugException(_text, null);
		}

		[Test]
		public void Test_DebugException()
		{
			_logger.DebugException(_text, _exception);
			TestMessage(LogLevel.Debug, false, true);
		}
		#endregion

		#region Test InfoException
		[Test]
		public void Test_InfoException_does_not_throw_for_null_message_param()
		{
			_logger.InfoException(null, _exception);
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Test_InfoException_throws_for_null_exception_param()
		{
			_logger.InfoException(_text, null);
		}

		[Test]
		public void Test_InfoException()
		{
			_logger.InfoException(_text, _exception);
			TestMessage(LogLevel.Info, false, true);
		}
		#endregion

		#region Test WarnException
		[Test]
		public void Test_WarnException_does_not_throw_for_null_message_param()
		{
			_logger.WarnException(null, _exception);
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Test_WarnException_throws_for_null_exception_param()
		{
			_logger.WarnException(_text, null);
		}

		[Test]
		public void Test_WarnException()
		{
			_logger.WarnException(_text, _exception);
			TestMessage(LogLevel.Warn, false, true);
		}
		#endregion

		#region Test ErrorException
		[Test]
		public void Test_ErrorException_does_not_throw_for_null_message_param()
		{
			_logger.ErrorException(null, _exception);
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Test_ErrorException_throws_for_null_exception_param()
		{
			_logger.ErrorException(_text, null);
		}

		[Test]
		public void Test_ErrorException()
		{
			_logger.ErrorException(_text, _exception);
			TestMessage(LogLevel.Error, false, true);
		}
		#endregion

		#region Test FatalException
		[Test]
		public void Test_FatalException_does_not_throw_for_null_message_param()
		{
			_logger.FatalException(null, _exception);
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Test_FatalException_throws_for_null_exception_param()
		{
			_logger.FatalException(_text, null);
		}

		[Test]
		public void Test_FatalException()
		{
			_logger.FatalException(_text, _exception);
			TestMessage(LogLevel.Fatal, false, true);
		}
		#endregion

		#region Test LogException with Data
		[Test]
		public void Test_LogException_with_data_does_not_throw_for_null_message_param()
		{
			_logger.LogException(LogLevel.Debug, null, _data, _exception);
		}

		[Test]
		public void Test_LogException_with_data_does_not_throw_for_null_data_param()
		{
			_logger.LogException(LogLevel.Debug, _text, null, _exception);
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Test_LogException_with_data_throws_for_null_exception_param()
		{
			_logger.LogException(LogLevel.Debug, _text, _data, null);
		}

		[Test]
		public void Test_LogException_with_data_Debug()
		{
			_logger.LogException(LogLevel.Debug, _text, _data, _exception);
			TestMessage(LogLevel.Debug, true, true);
		}

		[Test]
		public void Test_LogException_with_data_Info()
		{
			_logger.LogException(LogLevel.Info, _text, _data, _exception);
			TestMessage(LogLevel.Info, true, true);
		}

		[Test]
		public void Test_LogException_with_data_Warn()
		{
			_logger.LogException(LogLevel.Warn, _text, _data, _exception);
			TestMessage(LogLevel.Warn, true, true);
		}

		[Test]
		public void Test_LogException_with_data_Error()
		{
			_logger.LogException(LogLevel.Error, _text, _data, _exception);
			TestMessage(LogLevel.Error, true, true);
		}

		[Test]
		public void Test_LogException_with_data_Fatal()
		{
			_logger.LogException(LogLevel.Fatal, _text, _data, _exception);
			TestMessage(LogLevel.Fatal, true, true);
		}
		#endregion

		#region Test DebugException with Data
		[Test]
		public void Test_DebugException_with_data_does_not_throw_for_null_message_param()
		{
			_logger.DebugException(null, _data, _exception);
		}

		[Test]
		public void Test_DebugException_with_data_does_not_throw_for_null_data_param()
		{
			_logger.DebugException(_text, null, _exception);
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Test_DebugException_with_data_throws_for_null_exception_param()
		{
			_logger.DebugException(_text, _data, null);
		}

		[Test]
		public void Test_DebugException_with_data()
		{
			_logger.DebugException(_text, _data, _exception);
			TestMessage(LogLevel.Debug, true, true);
		}
		#endregion

		#region Test InfoException with Data
		[Test]
		public void Test_InfoException_with_data_does_not_throw_for_null_message_param()
		{
			_logger.InfoException(null, _data, _exception);
		}

		[Test]
		public void Test_InfoException_with_data_does_not_throw_for_null_data_param()
		{
			_logger.InfoException(_text, null, _exception);
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Test_InfoException_with_data_throws_for_null_exception_param()
		{
			_logger.InfoException(_text, _data, null);
		}

		[Test]
		public void Test_InfoException_with_data()
		{
			_logger.InfoException(_text, _data, _exception);
			TestMessage(LogLevel.Info, true, true);
		}
		#endregion

		#region Test WarnException with Data
		[Test]
		public void Test_WarnException_with_data_does_not_throw_for_null_message_param()
		{
			_logger.WarnException(null, _data, _exception);
		}

		[Test]
		public void Test_WarnException_with_data_does_not_throw_for_null_data_param()
		{
			_logger.WarnException(_text, null, _exception);
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Test_WarnException_with_data_throws_for_null_exception_param()
		{
			_logger.WarnException(_text, _data, null);
		}

		[Test]
		public void Test_WarnException_with_data()
		{
			_logger.WarnException(_text, _data, _exception);
			TestMessage(LogLevel.Warn, true, true);
		}
		#endregion

		#region Test ErrorException with Data
		[Test]
		public void Test_ErrorException_with_data_does_not_throw_for_null_message_param()
		{
			_logger.ErrorException(null, _data, _exception);
		}

		[Test]
		public void Test_ErrorException_with_data_does_not_throw_for_null_data_param()
		{
			_logger.ErrorException(_text, null, _exception);
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Test_ErrorException_with_data_throws_for_null_exception_param()
		{
			_logger.ErrorException(_text, _data, null);
		}

		[Test]
		public void Test_ErrorException_with_data()
		{
			_logger.ErrorException(_text, _data, _exception);
			TestMessage(LogLevel.Error, true, true);
		}
		#endregion

		#region Test FatalException with Data
		[Test]
		public void Test_FatalException_with_data_does_not_throw_for_null_message_param()
		{
			_logger.FatalException(null, _data, _exception);
		}

		[Test]
		public void Test_FatalException_with_data_does_not_throw_for_null_data_param()
		{
			_logger.FatalException(_text, null, _exception);
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Test_FatalException_with_data_throws_for_null_exception_param()
		{
			_logger.FatalException(_text, _data, null);
		}

		[Test]
		public void Test_FatalException_with_data()
		{
			_logger.FatalException(_text, _data, _exception);
			TestMessage(LogLevel.Fatal, true, true);
		}
		#endregion
	}
}